package com.hlf.common.utils;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Properties;

import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPClientConfig;
import org.apache.commons.net.ftp.FTPFile;
import org.apache.commons.net.ftp.FTPListParseEngine;
import org.apache.commons.net.ftp.FTPReply;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;


@Component
public class FtpHelper {

    private static final Logger logger = LoggerFactory.getLogger(FtpHelper.class);

    private FTPClient ftp = null;
    /**
     * Ftp服务器
     */
    private String server;
    /**
     * 用户名
     */
    private String uname;

    /**
     * 密码
     */
    private String password;
    /**
     * 连接端口，默认21
     */
    private int port = 21;
    /**
     * basePath
     */

    private String storePath;

    private static InputStream inStream = null;

    private static Properties property = null;

    public FtpHelper() {
//        ClassLoader loader = FtpHelper.class.getClassLoader();
//        inStream = loader.getResourceAsStream("config.properties");
//        setArg(inStream);
//        ftp = new FTPClient();
    }


    /**
     * 设置参数
     *
     * @param instream 输入流
     */
    private void setArg(InputStream instream) {
        property = new Properties();
        BufferedInputStream inBuff = null;
        try {
            inBuff = new BufferedInputStream(instream);
            property.load(inBuff);
            uname = property.getProperty("username");
            password = property.getProperty("password");
            server = property.getProperty("ip");
            storePath = property.getProperty("storePath");
            port = Integer.parseInt(property.getProperty("port"));


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (inBuff != null)
                    inBuff.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 连接FTP服务器
     *
     * @return
     * @throws Exception
     */
    public FTPClient connectFTPServer() throws Exception {
        try {
            ftp.configure(getFTPClientConfig());
            ftp.connect(this.server, this.port);
            if (!ftp.login(this.uname, this.password)) {
                ftp.logout();
                ftp = null;
                return ftp;
            }

            // 文件类型,默认是ASCII
            ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
            ftp.setControlEncoding("GBK");
            // 设置被动模式
            ftp.enterLocalPassiveMode();
            ftp.setConnectTimeout(2000);
            ftp.setBufferSize(1024);
            // 响应信息
            int replyCode = ftp.getReplyCode();
            if ((!FTPReply.isPositiveCompletion(replyCode))) {
                // 关闭Ftp连接
                closeFTPClient();
                // 释放空间
                ftp = null;
                throw new Exception("登录FTP服务器失败,请检查![Server:" + server + "、"
                        + "User:" + uname + "、" + "Password:" + password);
            } else {
                return ftp;
            }
        } catch (Exception e) {
            ftp.disconnect();
            ftp = null;
            throw e;
        }
    }

    /**
     * 配置FTP连接参数
     *
     * @return
     * @throws Exception
     */
    public FTPClientConfig getFTPClientConfig() throws Exception {
        String systemKey = FTPClientConfig.SYST_NT;
        String serverLanguageCode = "zh";
        FTPClientConfig conf = new FTPClientConfig(systemKey);
        conf.setServerLanguageCode(serverLanguageCode);
        conf.setDefaultDateFormatStr("yyyy-MM-dd");
        return conf;
    }

    /**
     * 向FTP根目录上传文件
     *
     * @param localFile
     * @param newName
     *            新文件名
     * @throws Exception
     */
//    public Boolean uploadFile(String localFile, String newName)
//            throws Exception {
//        InputStream input = null;
//        boolean success = false;
//        try {
//            File file = null;
//            if (checkFileExist(localFile)) {
//                file = new File(localFile);
//            }
//            input = new FileInputStream(file);
//            success = ftp.storeFile(newName, input);
//            if (!success) {
//                throw new Exception("文件上传失败!");
//            }
//        } catch (Exception e) {
//            throw e;
//        } finally {
//            if (input != null) {
//                input.close();
//            }
//        }
//        return success;
//    }

    /**
     * 向FTP根目录上传文件
     *
     * @param input
     * @param newName 新文件名
     * @throws Exception
     */
    public Boolean uploadFile(InputStream input, String newName)
            throws Exception {
        boolean success = false;
        try {
            success = ftp.storeFile(newName, input);
            if (!success) {
                throw new Exception("文件上传失败!");
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (input != null) {
                input.close();
            }
        }
        return success;
    }

    /**
     * 向FTP指定路径上传文件
     *
     * @param localFile
     * @param newName        新文件名
     * @param remoteFoldPath
     * @throws Exception
     */

    public Boolean uploadFile(String localFile, String newName,
                              String remoteFoldPath) throws Exception {

        InputStream input = null;
        boolean success = false;
        try {
            File file = null;
            if (checkFileExist(localFile)) {
                file = new File(localFile);
            }
            input = new FileInputStream(file);

            // 改变当前路径到指定路径
            if (!this.changeDirectory(remoteFoldPath)) {
                logger.info("服务器路径不存!");
                return false;
            }
            success = ftp.storeFile(newName, input);
            if (!success) {
                throw new Exception("文件上传失败!");
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (input != null) {
                input.close();
            }
        }
        return success;
    }

    /**
     * 向FTP指定路径上传文件
     *
     * @param input
     * @param newName        新文件名
     * @param remoteFoldPath
     * @throws Exception
     */
    public Boolean uploadFile(InputStream input, String newName,
                              String remoteFoldPath) throws Exception {
        boolean success = false;
        try {
            // 改变当前路径到指定路径
            if (!this.changeDirectory(remoteFoldPath)) {
                logger.info("服务器路径不存!");
                return false;
            }
            success = ftp.storeFile(newName, input);
            if (!success) {
                throw new Exception("文件上传失败!");
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (input != null) {
                input.close();
            }
        }
        return success;
    }

    /**
     * 从FTP服务器下载文件
     *
     * @param remotePath FTP路径(不包含文件名)
     * @param fileName   下载文件名
     * @param localPath  本地路径
     */
    public Boolean downloadFile(String remotePath, String fileName,
                                String localPath) throws Exception {

        BufferedOutputStream output = null;
        boolean success = false;
        try {
            // 检查本地路径
            this.checkFileExist(localPath);
            // 改变工作路径
            if (!this.changeDirectory(remotePath)) {
                logger.info("服务器路径不存在");
                return false;
            }
            // 列出当前工作路径下的文件列表
            List<FTPFile> fileList = this.getFileList();
            if (fileList == null || fileList.size() == 0) {
                logger.info("服务器当前路径下不存在文件！");
                return success;
            }
            for (FTPFile ftpfile : fileList) {
                if (ftpfile.getName().equals(fileName)) {
                    File localFilePath = new File(localPath + File.separator
                            + ftpfile.getName());
                    output = new BufferedOutputStream(new FileOutputStream(
                            localFilePath));
                    success = ftp.retrieveFile(ftpfile.getName(), output);
                }
            }
            if (!success) {
                throw new Exception("文件下载失败!");
            }
        } catch (Exception e) {
            throw e;
        } finally {
            if (output != null) {
                output.close();
            }
        }
        return success;
    }

    /**
     * FTP文件上传
     *
     * @param localAdr  上传文件名
     * @param remoteAdr 指定的FTP目录
     * @return
     * @throws Exception
     */
    public boolean uploadFile(String localAdr, String remoteAdr) throws Exception {
        boolean success = false;
        // 设置PassiveMode传输
        ftp.enterLocalPassiveMode();

        // 设置FTP文件类型为二进制，如果缺省该句 传输txt正常 但图片和其他格式的文件传输出现乱码
        ftp.setFileType(FTP.BINARY_FILE_TYPE);
        /*****对远程目录的处理******/
        String remoteFileName = remoteAdr;

        if (remoteAdr.contains("/")) {
            remoteFileName = remoteAdr.substring(remoteAdr.lastIndexOf("/") + 1);
            String directory = remoteAdr.substring(0, remoteAdr.lastIndexOf("/") + 1);
            if (!directory.equalsIgnoreCase("/") && !ftp.changeWorkingDirectory(directory)) {

                // 如果远程目录不存在，则递归创建远程服务器目录
                int start = 0, end = 0;

                if (directory.startsWith("/")) {
                    start = 1;
                } else {
                    start = 0;
                }

                end = directory.indexOf("/", start);

                while (true) {

                    String subDirectory = remoteAdr.substring(start, end);

                    if (!ftp.changeWorkingDirectory(subDirectory)) {

                        if (ftp.makeDirectory(subDirectory)) {

                            ftp.changeWorkingDirectory(subDirectory);

                        } else {
                            return false;
                        }
                    }
                    start = end + 1;
                    end = directory.indexOf("/", start);
                    // 检查所有目录是否创建完毕
                    if (end <= start) {
                        break;
                    }
                }
            }
        }

        /*****执行文件上传******/
        InputStream input = null;
        try {
            File f = new File(localAdr);
            // 得到目录的相应文件列表
//             FTPFile[] fs = ftp.listFiles(remoteFileName);

            //Log.getLogger(this.getClass()).info("上传文件个数:" + fs.length + "  ,文件名称:" + localAdr);

            input = new FileInputStream(f);
            // 保存文件remoteFileName
            success = ftp.storeFile(remoteFileName, input);
            input.close();
        } catch (IOException e) {
            //Log.getLogger(this.getClass()).info("上传文件失败:" + e.getMessage());
            if (input != null) {
                input.close();
            }
        } finally {
            //Log.getLogger(this.getClass()).info("保存标识>>>" + success + "文件名称:" + localAdr + (success ? "上传成功!" : "上传失败!"));
            // free();    
        }
        return success;

    }

    /**
     * 释放FTP
     */
    public void free() {
        if (ftp.isConnected()) {
            try {
                // 断开连接    
                ftp.disconnect();
            } catch (IOException e) {
                //Log.getLogger(this.getClass()).error("FTP断开连接异常:" + e.getMessage());    
            }
        }
    }

    /**
     * 从FTP服务器获取文件流
     *
     * @param remoteFilePath
     * @return
     * @throws Exception
     */
    public InputStream downloadFile(String remoteFilePath) throws Exception {

        return ftp.retrieveFileStream(remoteFilePath);
    }

    /**
     * 获取FTP服务器上指定路径下的文件列表
     *
     * @param remotePath
     * @return
     */
    public List<FTPFile> getFtpServerFileList(String remotePath)
            throws Exception {

        FTPListParseEngine engine = ftp.initiateListParsing(remotePath);
        List<FTPFile> ftpfiles = Arrays.asList(engine.getNext(25));

        return ftpfiles;
    }

    /**
     * 获取FTP服务器上[指定路径]下的文件列表
     *
     * @param remotePath
     * @return
     * @throws Exception
     */
    public List<FTPFile> getFileList(String remotePath) throws Exception {

        List<FTPFile> ftpfiles = Arrays.asList(ftp.listFiles(remotePath));

        return ftpfiles;
    }

    /**
     * 获取FTP服务器[当前工作路径]下的文件列表
     *
     * @return
     * @throws Exception
     */
    public List<FTPFile> getFileList() throws Exception {

        List<FTPFile> ftpfiles = Arrays.asList(ftp.listFiles());

        return ftpfiles;
    }

    /**
     * 改变FTP服务器工作路径
     *
     * @param remoteFoldPath
     */
    public Boolean changeDirectory(String remoteFoldPath) throws Exception {

        return ftp.changeWorkingDirectory(remoteFoldPath);
    }

    /**
     * 删除文件
     *
     * @param remoteFilePath
     * @return
     * @throws Exception
     */
    public Boolean deleteFtpServerFile(String remoteFilePath) throws Exception {

        return ftp.deleteFile(remoteFilePath);
    }

    /**
     * 创建目录
     *
     * @param remoteFoldPath
     * @return
     */
    public boolean createFold(String remoteFoldPath) throws Exception {

        boolean flag = ftp.makeDirectory(remoteFoldPath);
        if (!flag) {
            throw new Exception("创建目录失败");
        }
        return false;
    }

    /**
     * 删除目录
     *
     * @param remoteFoldPath
     * @return
     * @throws Exception
     */
    public boolean deleteFold(String remoteFoldPath) throws Exception {

        return ftp.removeDirectory(remoteFoldPath);
    }

    /**
     * 删除目录以及文件
     *
     * @param remoteFoldPath
     * @return
     */
    public boolean deleteFoldAndsubFiles(String remoteFoldPath)
            throws Exception {

        boolean success = false;
        List<FTPFile> list = this.getFileList(remoteFoldPath);
        if (list == null || list.size() == 0) {
            return deleteFold(remoteFoldPath);
        }
        for (FTPFile ftpFile : list) {

            String name = ftpFile.getName();
            if (ftpFile.isDirectory()) {
                success = deleteFoldAndsubFiles(remoteFoldPath + "/" + name);
                if (!success)
                    break;
            } else {
                success = deleteFtpServerFile(remoteFoldPath + "/" + name);
                if (!success)
                    break;
            }
        }
        if (!success)
            return false;
        success = deleteFold(remoteFoldPath);
        return success;
    }

    /**
     * 检查本地路径是否存在
     *
     * @param filePath
     * @return
     * @throws Exception
     */
    public boolean checkFileExist(String filePath) throws Exception {
        boolean flag = false;
        File file = new File(filePath);
        if (!file.exists()) {
            throw new Exception("本地路径不存在,请检查!");
        } else {
            flag = true;
        }
        return flag;
    }


    /**
     * 关闭FTP连接
     *
     * @param ftp
     * @throws Exception
     */
    public void closeFTPClient(FTPClient ftp) throws Exception {

        try {
            if (ftp.isConnected())
                ftp.logout();
            ftp.disconnect();
        } catch (Exception e) {
            throw new Exception("关闭FTP服务出错!");
        }
    }

    /**
     * 关闭FTP连接
     *
     * @throws Exception
     */
    public void closeFTPClient() throws Exception {

        this.closeFTPClient(this.ftp);
    }

    /**
     * Get Attribute Method
     */
    public FTPClient getFtp() {
        return ftp;
    }

    public String getServer() {
        return server;
    }

    public String getUname() {
        return uname;
    }

    public String getPassword() {
        return password;
    }

    public int getPort() {
        return port;
    }

    /**
     * Set Attribute Method
     */
    public void setFtp(FTPClient ftp) {
        this.ftp = ftp;
    }

    public void setServer(String server) {
        this.server = server;
    }

    public void setUname(String uname) {
        this.uname = uname;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public String getStorePath() {
        return storePath;
    }


    public void setStorePath(String storePath) {
        this.storePath = storePath;
    }


    /**
     * 主方法(测试)
     * <p>
     * 问题：上传时命名的新文件名不能有中文，否则上传失败.
     *
     * @param args
     */
    public static void main(String[] args) {
        try {
            FtpHelper fu = new FtpHelper();
            fu.connectFTPServer();
            fu.deleteFtpServerFile("/webapps/imgftpservice/image/s20140725755000008/0_20140828142956866.jpg");
            //fu.uploadFile("E:\\1236950906793.jpg", fu.storePath+"/s20140725755000019/1236950906793.jpg");
            fu.closeFTPClient();
            //fu.createFold("/webapps");
            //log.info(fu.getFileList().size());
//            Element fatherElement = fu.getCurrentElement();
//            fu.createDirectoryXML("/", fatherElement);
//            fu.saveXML();
        } catch (Exception e) {
            logger.info("异常信息：" + e.getMessage());
        }
    }
}  
